package com.ruicar.afs.cloud.common.voucher.handle;

import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ruicar.afs.cloud.common.voucher.Voucher;
import com.ruicar.afs.cloud.common.voucher.VoucherResult;
import com.ruicar.afs.cloud.common.voucher.VoucherRunResult;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

@Slf4j
public class ParallelVoucherRunner extends AbstractRunner {

    private static final ExecutorService EXECUTOR_SERVICE = new ThreadPoolExecutor(5, 10,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<Runnable>(1024));

    /**
     * Execute voucher run result
     * <p>Description: </p>
     *
     * @param vouchers     vouchers
     * @param mapParam voucher param
     * @return the voucher run result
     */
    @Override
    public VoucherRunResult execute(List<Voucher> vouchers, Map<String,Object> mapParam) {
        List<VoucherResult> resultList = Collections.synchronizedList(new ArrayList<>());
        CountDownLatch countDownLatch = new CountDownLatch(vouchers.size());
        try {
            for (Voucher voucher : vouchers) {
                EXECUTOR_SERVICE.submit(new VoucherRunner(voucher, resultList, genVoucherContext(voucher, mapParam), countDownLatch));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                log.error("", e);
            }
        }
        return VoucherRunResult.builder().hit(!resultList.isEmpty()).results(resultList).build();
    }

    @AllArgsConstructor
    private static class VoucherRunner implements Runnable {
        private Voucher voucher;
        private List<VoucherResult> voucherList;
        private DefaultContext context;
        private CountDownLatch countDownLatch;

        @Override
        public void run() {
            ExpressRunner runner = new ExpressRunner();
            try {
                BigDecimal result = (BigDecimal) runner.execute(voucher.getRuleExpress(),context , null, true, true);
                VoucherResult voucherResult = new VoucherResult();
                voucherResult.setRuleNo(voucher.getRuleNo());
                voucherResult.setAmt(result);
                voucherList.add(voucherResult);
            } catch (Exception e) {
                log.error("", e);
            } finally {
                countDownLatch.countDown();
            }
        }
    }
}
